#include <fstream>
#include <pthread.h>
#include "MultiClient.h"
#include "../time_controller/TimeController.h"
#include <map>
#include <stdlib.h>

void* multi_select (void*)
{
	string buff, vr_addr_str, sql;
	ofstream db_log;
	map<string, ClientSocket*> client_map;
	map<int, TimeController*> controllers;
	//cout << "yes" << endl;

	try
	{
		Connection conn("vrwebmonitor", "127.0.0.1", "root", "bwu929as");
		Query query(conn.query());

		sql = "select * from vrlist;";
		if (UseQueryResult res = query.use(sql))
		{
			//应该在此加入判断：如果选到的行数大于0才进入循环
			while (Row row = res.fetch_row())
			{
				try 
				{
					sql.clear();
					row["vraddr"].to_string(vr_addr_str);
					client_map[vr_addr_str] = new ClientSocket();
					client_map[vr_addr_str]->sock_nonblock(true);
					client_map[vr_addr_str]->conn(vr_addr_str, row["port"]);
					client_map[vr_addr_str]->set_connected(true);
				}
				catch (const SocketException& e)
				{
					//如果连接不成功应该将此套接口注销重建，因为每个套接字只能被connect一次
					//delete client_map[vr_addr_str];
					//client_map[vr_addr_str] = new ClientSocket();
					//client_map[vr_addr_str]->sock_nonblock(true);
					cout << __LINE__ << " Socket exception was caught, when init a client obj: " << endl;
					update_vr_connection(vr_addr_str, BAD_CONNECTION);
					cout << __LINE__ << e.description() << endl;
					cout << "The map key word is:" << vr_addr_str << endl << endl;
				}
				catch (const Exception& er)
				{
					record_to_logfile(db_log, er.what(), sql, __LINE__, __FUNCTION__, __FILE__);
				}
			}
			if (conn.errnum())
			{
				record_to_logfile(db_log, conn.error(), sql, __LINE__, __FUNCTION__, __FILE__);
			}
		}
		else
		{
			record_to_logfile(db_log, query.error(), sql, __LINE__, __FUNCTION__, __FILE__);
		}
		conn.disconnect();
		map<string, ClientSocket*>::iterator iter;

		//更新VR状态在数据库中的显示
		for (iter = client_map.begin(); iter != client_map.end(); iter++)
		{
			if (iter->second->is_connected())
			{
				try
				{
					update_vr_connection(iter->first, GOOD_CONNECTION);
				}
				catch (const Exception& er)
				{
					record_to_logfile(db_log, er.what(), sql, __LINE__, __FUNCTION__, __FILE__);
				}
			}
		}
		struct in6_addr vr_addr;
		
		//向所有连接良好的VR发送数据请求报文
		for (iter = client_map.begin(); iter != client_map.end(); iter++)
		{
			try 
			{
				if (iter->second->is_connected())
				{
					*(iter->second) << send_msg(SEND_STAT_ALL_ONCE);
					cout << __LINE__ << ": SEND_STAT_ALL_ONCE sent." << endl;
					*(iter->second) >> buff;
					vr_addr = iter->second->get_server_addr6();
					send2db(vr_addr, buff);
					//*/

					///*
					*(iter->second) << send_msg(SEND_PATH_ALL_ONCE);
					cout << __LINE__ << ": SEND_PATH_ALL_ONCE sent." << endl;
					*(iter->second) >> buff;
					send2db(vr_addr, buff);
					iter->second->set_info_received(true);
					//*/
				}
			}
			catch (const BadConnection& e)
			{
				cout << __LINE__ << " Socket exception was caught, when send instructions to vr: " << endl;
				cout << e.description() << endl;
				cout << __LINE__ << "The map key word is:" << iter->first << endl;
			}
			catch (const SocketException& e)
			{
				cout << __LINE__ << " Socket exception was caught, when send instructions to vr: " << endl;
				cout << e.description() << endl;
				cout << __LINE__ << "The map key word is:" << iter->first << endl << endl;
			}
		}

		ServerSocket server_sock (PHP_SERV_PORT);
		cout << "PHP server prepared in port 3000." << endl;

		struct in6_addr ipv6_addr;
		struct timeval timer;
		time_t clock_value, clock_inter;
		fd_set rset, wset;
		int maxfdp1, slt, readfd;
		map<int, TimeController*>::iterator it;
		while (true)
		{
			FD_ZERO(&rset);
			FD_ZERO(&wset);
			int maxfd = 0;
			timer.tv_sec = 1;
			timer.tv_usec = 0;

			for (iter = client_map.begin(); iter != client_map.end(); iter++)
			{
				//把连接良好或正在连接中的套接字注册到select的读检测集合中
				if ( iter->second->is_connected() || iter->second->is_connecting() )
				{
					FD_SET(iter->second->sock_fd(), &rset);
					maxfd = max(maxfd, iter->second->sock_fd());
				}
				//把正在连接中的套接字注册到select的写检测集合中
				if ( iter->second->is_connecting() )
				{
					FD_SET(iter->second->sock_fd(), &wset);
					maxfd = max(maxfd, iter->second->sock_fd());
				}
			}
			cout << "now the container size is :" << client_map.size() << endl;
			FD_SET(server_sock.sock_fd(), &rset);
			//cout << __LINE__ << " server sockfd is : " << server_sock.sock_fd() << endl;
			maxfd = max (server_sock.sock_fd(), maxfd);
			maxfdp1 = maxfd + 1;
			//cout << "maxfdp1 : " << maxfdp1 << endl;

			if ( (slt = select(maxfdp1, &rset, &wset, NULL, &timer)) < 0)
			{
				perror("select error: ");
				exit(1);
			}
			
			clock_inter = time(NULL) - clock_value;

			//cout << clock_inter << " " << clock_value << endl;
			//数据到达密集的时候（假设不到一秒就会有数据到达），slt永远不会为0，因此不能用此判断作为进入定时器的入口
			//if ( slt == 0 )
			//不论select因何种原因向下执行了，只要距离上次执行超过1秒的间隔，那么定时器就开始执行
			if (clock_inter >= 1)
			{
				clock_value = time(NULL);
				cout << __LINE__ << ": in timer." << endl;
				for (iter = client_map.begin(); iter != client_map.end(); iter++)
				{
					if (iter->second->timer_count() < 7)
					{
						iter->second->timer_count(SELF_INCR);
					}
					else	//keep alive block here
					{
						iter->second->timer_count(SET_ZERO);
						//如果发送保活报文之前连接是良好的
						if ( iter->second->is_connected() )
						{
							if (iter->second->kep_alive_times() < 4)	//发送3次保活报文
							{
								iter->second->kep_alive_times(SELF_INCR);
								buff.clear();
								char tmp_ch = 6;
								string keep_alive_msg(&tmp_ch, 1);
								try
								{
									update_vr_connection(iter->first, GOOD_CONNECTION);
									*(iter->second) << keep_alive_msg;
									cout << iter->second->kep_alive_times() << " keep alive have sent to " << iter->first << __LINE__ <<endl;
									//cout << __LINE__ << " keep alive msg size is: " << keep_alive_msg.size() << endl;
								}
								catch (SocketException& e)
								{
									cout << __LINE__ << " keep alive could not sent." << endl;
									cout << "Exception was caught: " << e.description() << __LINE__ << endl;
								}
							}
							else
							{
								//连接由好变坏的时刻，将数据库中的连接状态更新为down
								update_vr_connection(iter->first, BAD_CONNECTION);
								cout << iter->first << " Down diaola! in line " << __LINE__ << endl;
								//why sleep?
								sleep(2);
								//和server端失去连接后，不能在原有的套接字上进行重新连接，否则将出错
								//必须删除旧套接字，并且重新申请套接字
								delete iter->second;
								iter->second = new ClientSocket();
								iter->second->sock_nonblock(true);
							}
						}
						//如果发送保活报文之前连接是不好的，发起连接
						else if ( !iter->second->is_connecting() )
						{
							try
							{
								//重新连接容器中已有的连接不好的VR
								cout << __LINE__ << " reconnecting... " << endl;
								iter->second->conn(iter->first, VR_SERV_PORT);
								//*(iter->second) << send_msg(SEND_STAT_ALL_ONCE);
								cout << __LINE__ << " reconnected." << endl;
								iter->second->set_connected(true);
								//连接由坏变好的时刻，将数据库中的连接状态更新为up
								update_vr_connection(iter->first, GOOD_CONNECTION);
								cout << iter->first << " Up le! " << __LINE__ << endl;
								//sleep(1);
								*(iter->second) << send_msg(SEND_PATH_ALL_ONCE);
								FD_SET(iter->second->sock_fd(), &rset);
							}
							catch(SocketException& e)
							{
								cout << "Exception was caught: " << e.description() << __LINE__ << endl;
							}
						}
					}//keep alive block end
				}//对连接对象的遍历结束
				if (controllers.size())
				{
					for (it = controllers.begin(); it != controllers.end(); it++)
					{
						cout << "timer checking ..." << endl;
						if (it->second->OnTime())
						{
							try
							{
								cout << "timer msg sending ..." << endl;
								it->second->ConnObjVR();
								it->second->MsgSend();
							}
							catch (SocketException& e)
							{
								cout << "Exception was caught: " << e.description() << __LINE__ << endl;
							}
							delete controllers[it->first];
							controllers.erase(it->first);
						}
					}
				}
			}
			if ( FD_ISSET(server_sock.sock_fd(), &rset) )	//from PHP
			{
				cout << slt << " socket come from PHP." << endl;
				try 
				{
					ServerSocket new_sock;
					server_sock.accept(new_sock);
					new_sock >> buff;
					cout << "recv buff size is : " << buff.size() << endl;
					int type = buff[0];
					int len = buff[1];
					int pos;
					char tmp_str[ADDR6STRLEN];

					cout << "type : " << type << " length : " << len << endl;
					if (TIME_COTL_MSG == type)
					{
						int interval;
						int buffsize = buff.size();
						string ctrlmsg;
						int i = 0;
						while (buffsize > 24)
						{
							try
							{
								cout << "msg unpack ... " << __LINE__ << endl;
								interval = *(int*)(buff.substr(buffsize - 4)).c_str();
								cout << "after " << interval << " seconds, this msg will be sent." << endl;
								memcpy(&ipv6_addr, (buff.substr(buffsize - 20, 16)).c_str(), 16);
								inet_ntop(AF_INET6, (void*)&ipv6_addr, tmp_str, sizeof(tmp_str));
								vr_addr_str = tmp_str;
								ctrlmsg = buff.substr(buffsize - 24, 4);
								buff.erase(buffsize - 24);
								buffsize -= 24;
								controllers[i++] = new TimeController(vr_addr_str, ctrlmsg, interval);
							}
							catch (exception& e)
							{
								cout << e.what() << endl;
							}
						}
						cout << "controllers size is : " << controllers.size() << endl;

						/*
						pthread_t tid;
						pthread_create(&tid, NULL, InstSendTimer, (void*)&buff);
						pthread_join(tid, 0);
						*/
					}
					else
					{
						///*
						cout << "not time msg came." << endl;
						pos = buff.size() - 16;
						if (pos > 0)
						{
							memcpy(&ipv6_addr, (buff.substr(pos)).c_str(), 16);
						}
						else
						{
							cout << "error";
						}
						//inet_ntop(AF_INET6, (void*)(buff.substr(pos)).c_str(), tmp_str, 40);
						inet_ntop(AF_INET6, (void*)&ipv6_addr, tmp_str, sizeof(tmp_str));
						vr_addr_str = tmp_str;
						//ipv6_addr = (struct in6_add)(buff.substr(pos)).c_str();

						//cout << "the object addr is " << vr_addr_str << endl;
						buff.erase(pos);
						//cout << "type value is : " << type << endl;
						if ( VLINK_STAT_MSG==type || VLINK_COTL_MSG==type || VLINK_PATH_MSG==type || VLINK_CONF_MSG==type )
						{
							try
							{
								cout << "type = " << type;
								cout << "oper = " << (int)buff[1];
								cout << "vlink_no = " << (int)buff[2];
								//cout << "hello_int = " << (int)(buff.substr(3,2).c_str());

								cout << "sent buff size is: " << buff.size() << endl;
								*(client_map[vr_addr_str]) << buff;
								cout << "Inst have been sent." << endl;
							}
							catch (const SocketException& e)
							{
								cout << "Exception was caught: " << e.description() << endl;
								client_map[vr_addr_str]->set_connected(false);
								client_map[vr_addr_str]->set_info_received(false);
								update_vr_connection(vr_addr_str, BAD_CONNECTION);

								/*
								   sql.clear();
								   sql = "update vrlist set linkstate=0 where vraddr=\"" + vr_addr_str + "\";";
								   query.use(sql);
								   sql.clear();
								   sql = form_vrlistlog_sql(vr_addr_str, BAD_CONNECTION);
								   query.use(sql);
								 */
							}
						}
						else if (VR_ADD_DEL_MSG == type)
						{
							if (ADD_VR == buff[1])
							{
								try
								{
									cout << __LINE__ << ": add new vr " << vr_addr_str << endl;
									client_map[vr_addr_str] = new ClientSocket();
									client_map[vr_addr_str]->sock_nonblock(true);
									client_map[vr_addr_str]->conn(vr_addr_str, VR_SERV_PORT);
									client_map[vr_addr_str]->set_connected(true);
									sleep(1);
									//cout << client_map[vr_addr_str]->is_connected() << endl;
									//cout << __LINE__ << ": " <<  client_map[vr_addr_str]->sock_fd() << endl;
									//client_map[vr_addr_str]->sock_nonblock(true);

									update_vr_connection(vr_addr_str, GOOD_CONNECTION);

									//cout << __LINE__ << ": tend to send1." << endl;
									//cout << __LINE__ << ": " <<  client_map[vr_addr_str]->sock_fd() << endl;
									//client_map[vr_addr_str]->sock_nonblock(true);
									*(client_map[vr_addr_str]) << send_msg(SEND_STAT_ALL_ONCE);
									//cout << __LINE__ << ": tend to send2.";
									/*(client_map[vr_addr_str]) >> buff;
									  vr_addr = client_map[vr_addr_str]->get_server_addr6();
									  send2db(vr_addr, buff);
									 */
									sleep(1);

									//*(client_map[vr_addr_str]) << send_msg(SEND_PATH_ALL_ONCE);
									/*(client_map[vr_addr_str]) >> buff;
									  vr_addr = client_map[vr_addr_str]->get_server_addr6();
									  send2db(vr_addr, buff);
									  client_map[vr_addr_str]->set_info_received(true);
									 */
									//FD_SET(client_map[vr_addr_str]->sock_fd(), &rset);
								}
								catch(const BadConnection& e)
								{
									cout << __LINE__ << " Exception was caught: ()" << e.description() << endl;
								}
								catch (const SocketException& e)
								{
									cout << __LINE__ << " socket fd is: " <<  client_map[vr_addr_str]->sock_fd() << endl;
									cout << __LINE__ << " Exception was caught (end): " << e.description() << endl;
								}
								/*
								   catch (const BadQuery& er)
								   {
								   record_to_logfile(db_log, er.what(), sql, __LINE__, __FUNCTION__, __FILE__);
								   }
								 */
								catch (const Exception& er)
								{
									record_to_logfile(db_log, er.what(), sql, __LINE__, __FUNCTION__, __FILE__);
								}
								catch(exception& e)
								{
									cout << e.what() << endl;
								}
							}
							else if (DEL_VR == buff[1])
							{
								cout << __LINE__ << ": delete vr: " << vr_addr_str << endl;
								delete client_map[vr_addr_str];
								client_map.erase(vr_addr_str);
								cout << __LINE__ << " not exec? " << endl;
								cout << __LINE__ << " the container size became :" << client_map.size() << endl;
								for (iter = client_map.begin(); iter != client_map.end(); iter++)
								{
									cout << iter->first << " " << iter->second->sock_fd() << endl;
								}
							}
						}
					}
					//*/
				}
				catch (const SocketException& e)
				{
					cout << "Exception was caught : " << e.description() << __LINE__ << endl;
					record_to_logfile(db_log, e.description().c_str(), "Socket error.", __LINE__, __FUNCTION__, __FILE__);
				}
				catch (const exception& e)
				{
					cout << "Exception was caught : " << e.what() << __LINE__ << endl;
					record_to_logfile(db_log, e.what(), "", __LINE__, __FUNCTION__, __FILE__);
				}
			}
			else	//not from PHP, but from VR
			{
				for (iter = client_map.begin(); iter != client_map.end(); iter++)
				{
					//这里检查发起的连接是否成功
					if ( iter->second->is_connecting() && (FD_ISSET(iter->second->sock_fd(), &rset) || FD_ISSET(iter->second->sock_fd(), &wset)) )
					{
						try 
						{
							cout << "in file " << __FILE__ << " line " << __LINE__ << endl;
							if (iter->second->nonblock_connection_success())
							{
								cout << __LINE__ << " vr " << iter->first << " first time connected." << endl;
								iter->second->set_connected(true);
								iter->second->sock_nonblock(false);
								*(iter->second) << send_msg(SEND_STAT_ALL_ONCE);
								//连接由坏变好的时刻，将数据库中的连接状态更新为up
								update_vr_connection(iter->first, GOOD_CONNECTION);

								*(iter->second) << send_msg(SEND_PATH_ALL_ONCE);
								//FD_SET(iter->second->sock_fd(), &rset);
								FD_CLR( iter->second->sock_fd(), &rset );		/* no more writeability test */
							}
						}
						catch (SocketException& er)
						{
							delete iter->second;
							iter->second = new ClientSocket();
							iter->second->sock_nonblock(true);

							cout << "in file " << __FILE__ << " line " << __LINE__ << er.description() << endl;
						}
					} 
					//读套接口上的数据，并处理
					if ( FD_ISSET(iter->second->sock_fd(), &rset) )
					{
						try
						{
							buff.clear();
							cout << endl << slt << " socket data arrived, now process data from " << iter->first << endl;
							*(iter->second) >> buff;
							if ( 1==buff.size() && ECHO_MSG==buff[0] )
							{
								cout << __LINE__ << " recv keep alive echo data." << endl;
								iter->second->kep_alive_times(SET_ZERO);
							}
							else
							{
								cout << __LINE__ << " the buff size is: " << buff.size() << endl;
								vr_addr = iter->second->get_server_addr6();
								send2db(vr_addr, buff);
							}
							iter->second->set_connected(true);
							update_vr_connection(iter->first, GOOD_CONNECTION);
						}
						catch (SocketException& er)
						{
							cout << "in file " << __FILE__ << " line " << __LINE__ << er.description() << endl;
						}
						catch (exception& er)
						{
							cout << "in file " << __FILE__ << " line " << __LINE__ << er.what() << endl;
						}
					}
				}
			}
		}
	}
	catch (const SocketException& e)
	{
		cout << "Exception was caught (end): " << e.description() << __LINE__ << endl;
	}
	catch (const Exception& er)
	{
		record_to_logfile(db_log, er.what(), sql, __LINE__, __FUNCTION__, __FILE__);
		cout << __LINE__ << endl;
	}
	catch (exception& er)
	{
		cout << "in file " << __FILE__ << " line " << __LINE__ << er.what() << endl;
	}
}
//end of function multi_select()

void form_path_time (char* path, char* hms)
{
	struct tm* nowtime;
	time_t nt = time(NULL);
	nowtime = localtime(&nt);
	//增加判断文件夹是否存在的语句
	strftime(path, 30, "./log_files/%F.db.log", nowtime);
	strftime(hms, 10, "%T", nowtime);
}

string form_vrlistlog_sql (string addr, const bool conn_stat)
{
	string sql;
	char tmp[15];
	sql += "insert into vrlistlog (vraddr, linkstate, time) values (\"";
	sql += addr + "\", ";
	sprintf(tmp, "%d", conn_stat);
	sql += tmp;
	sql += ", ";
	time_t nt = time(NULL);
	sprintf(tmp, "%d", (int)nt);
	sql += tmp;
	sql += ");";
	return sql;
}

void update_vr_connection (const string addr, const bool conn_stat)
{
		ofstream db_log;
		string sql;
		try
		{
				Connection conn("vrwebmonitor", "127.0.0.1", "root", "bwu929as");
				Query query(conn.query());

				char tmp[15];
				sprintf(tmp, "%d", conn_stat);
				sql += "update vrlist set linkstate=";
				sql += tmp;
				sql += " where vraddr=\"" + addr + "\";";
				query.use(sql);
				sql.clear();
				sql += "insert into vrlistlog (vraddr, linkstate, time) values (\"";
				sql += addr + "\", ";
				sql += tmp;
				sql += ", ";
				time_t nt = time(NULL);
				sprintf(tmp, "%d", (int)nt);
				sql += tmp;
				sql += ");";
				//cout << "in update_vr_connection: " << sql << endl;
				query.use(sql);
				//cout << "in update_vr_connection: " << sql << endl;
				conn.disconnect();
				//cout << "in update_vr_connection: " << sql << endl;
		}
		catch (const Exception& er)
		{
				record_to_logfile(db_log, er.what(), sql, __LINE__, __FUNCTION__, __FILE__);
				//cout << "line " << __LINE__ << " in file " << __FILE__ << endl;
		}
}

void record_to_logfile (ofstream& db_log, const char* what, const string sql, const int line, const char* func, const char* file)
{
	char log_file_path[30], h_m_s[10];
	form_path_time(log_file_path, h_m_s);
	db_log.open(log_file_path, ios::app);
	db_log << "error: " << what << " [" << sql << "] [" << h_m_s << "] ";
	db_log << "[file:" << file << "] [func:" << func << "] [line:" << line << "]" << endl;
}

